/*
 * @Author: 朽木白
 * @Date: 2023-02-06 11:02:58
 * @LastEditors: 1547702880@@qq.com
 * @LastEditTime: 2023-03-25 09:55:02
 * @Description: axios请求封装
 */
import { LOGIN_URL } from '@/config/config'
import { ResultEnum } from '@/enums/httpEnums'
import router from '@/router'
import { useUserStore } from '@/store/modules/user'

import type {
  AxiosError,
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { RESEETSTORE } from '../reset'
import { ResultData } from './type'

interface FailedQueue {
  resolve: (value: unknown) => void
  reject: (reason?: any) => void
}

const userStore = useUserStore()

export const service: AxiosInstance = axios.create({
  // 判断环境设置不同的baseURL
  baseURL: import.meta.env.PROD ? import.meta.env.VITE_APP_BASE_URL : '/',
  timeout: ResultEnum.TIMEOUT as number,
})
/**
 * @description: 请求拦截器
 * @returns {*}
 */
service.interceptors.request.use(
  (config) => {
    const token = userStore.accessToken
    if (token) {
      config.headers['Authorization'] = 'Bearer ' + token
    }
    return config
  },
  (error: AxiosError) => {
    ElMessage.error(error.message)
    return Promise.reject(error)
  },
)
/**
 * @description: 响应拦截器
 * @returns {*}
 */
let isRefreshing = false
let failedQueue: Array<FailedQueue> = []

const processQueue = (error: any, token = null) => {
  failedQueue.forEach((prom) => {
    console.log('prom:', prom)

    if (error) {
      prom.reject(error)
    } else {
      prom.resolve(token)
    }
  })
  failedQueue = []
}

service.interceptors.response.use(
  (response: AxiosResponse) => {
    const { data } = response
    // * 登陆失效
    if (ResultEnum.EXPIRE.includes(data.code)) {
      RESEETSTORE()
      ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
      router.replace(LOGIN_URL)
      return Promise.reject(data)
    }

    if (data.code && data.code !== ResultEnum.SUCCESS) {
      ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
      return Promise.reject(data)
    }
    return data
  },
  (error: AxiosError) => {
    // // 处理 HTTP 网络错误
    // let message = ''
    // // HTTP 状态码
    // const status = error.response?.status
    // switch (status) {
    //   case 401:
    //     message = 'token 失效，请重新登录'
    //     break
    //   case 403:
    //     message = '拒绝访问'
    //     break
    //   case 404:
    //     message = '请求地址错误'
    //     break
    //   case 500:
    //     message = '服务器故障'
    //     break
    //   default:
    //     message = '网络连接故障'
    // }

    // ElMessage.error(message)
    // return Promise.reject(error)
    const originalRequest = {
      ...(error.config as InternalAxiosRequestConfig<any>),
      _retry: false,
    }

    if (error.response?.status === 403 && !originalRequest._retry) {
      if (isRefreshing) {
        return new Promise((resolve, reject) => {
          failedQueue.push({ resolve, reject })
        })
          .then(() => {
            originalRequest.headers[
              'Authorization'
            ] = `Bearer ${userStore.accessToken}`
            return service(originalRequest)
          })
          .catch((err) => {
            return Promise.reject(err)
          })
      }

      originalRequest._retry = true
      isRefreshing = true

      const refreshToken = userStore.refreshToken
      if (!refreshToken) {
        router.push('/login')
        return Promise.reject(error)
      }

      return new Promise((resolve, reject) => {
        axios
          .post('/admin/refreshToken', refreshToken, {
            headers: {
              Authorization: 'Bearer ' + refreshToken,
            },
          })
          .then(({ data: { data: tokenData } }) => {
            userStore.setToken(tokenData)
            originalRequest.headers[
              'Authorization'
            ] = `Bearer ${tokenData.accessToken}`
            processQueue(null, tokenData.accessToken)
            resolve(service(originalRequest))
          })
          .catch((err) => {
            processQueue(err, null)
            userStore.Logout()
            router.push('/login')
            reject(err)
          })
          .finally(() => {
            isRefreshing = false
          })
      })
    }
    return Promise.reject(error)
  },
)

/**
 * @description: 导出封装的请求方法
 * @returns {*}
 */
const http = {
  get<T>(
    url: string,
    params?: object,
    config?: AxiosRequestConfig,
  ): Promise<ResultData<T>> {
    return service.get(url, { params, ...config })
  },

  post<T>(
    url: string,
    data?: object,
    config?: AxiosRequestConfig,
  ): Promise<ResultData<T>> {
    return service.post(url, data, config)
  },

  put<T>(
    url: string,
    data?: object,
    config?: AxiosRequestConfig,
  ): Promise<ResultData<T>> {
    return service.put(url, data, config)
  },

  delete<T>(
    url: string,
    data?: object,
    config?: AxiosRequestConfig,
  ): Promise<ResultData<T>> {
    return service.delete(url, { data, ...config })
  },
}

export default http
